import numpy as np
import pandas as pd
import holoviews as hv
from matplotlib import pyplot as plt
from scipy.sparse.csgraph import minimum_spanning_tree
from scipy.cluster.hierarchy import dendrogram, linkage
import json, re, datetime
import lens
import warnings
import itertools
hv.extension('bokeh')
W pierwszym kroku eksploracji wykorzystamy narzędzia udostępnione w pakiecie pandas. Moim zdaniem wystarczają one w większości zastosowań, ze względu na wysoką kompatybilność z najpopularniejszym standardem ramek danych w pythonie - pd.DataFrame. Następnie zaprezentuje możliwości biblioteki lens i opiszę jak wyglądało jej użycie
allegro_transactions = pd.read_csv('allegro-api-transactions.csv')
allegro_transactions.date = allegro_transactions.date.apply(lambda str_date_time : datetime.datetime.strptime(str_date_time, '%Y-%m-%d %H:%M:%S'))
allegro_transactions.info()
W celu zapewnienia poprawnego zachowania wbudowanych funkcji pd.DataFrame, przekształcimy kolumny na standardowe dla pandasa typy. Okazuje się, że lens nie radzi sobie z typami pd.Timestamp i pd.Categorical, co powinniśmy uznać za wadę pakietu, bo są to typy ze standardu biblioteki pandas.
Trzy podstawowe wbudowane narzędzia, z których korzysta się we wstępnej eksploracji danych to:
pandas_compliant_allegro_transactions = allegro_transactions.copy()
pandas_compliant_allegro_transactions.item_id = pd.Categorical(pandas_compliant_allegro_transactions.item_id)
pandas_compliant_allegro_transactions.pay_option_on_delivery = pd.Categorical(pandas_compliant_allegro_transactions.pay_option_on_delivery)
pandas_compliant_allegro_transactions.pay_option_transfer = pd.Categorical(pandas_compliant_allegro_transactions.pay_option_transfer)
pandas_compliant_allegro_transactions.seller = pd.Categorical(pandas_compliant_allegro_transactions.seller)
pandas_compliant_allegro_transactions.it_is_allegro_standard = pd.Categorical(pandas_compliant_allegro_transactions.it_is_allegro_standard)
pandas_compliant_allegro_transactions.it_is_brand_zone = pd.Categorical(pandas_compliant_allegro_transactions.it_is_brand_zone)
pandas_compliant_allegro_transactions.main_category = pd.Categorical(pandas_compliant_allegro_transactions.main_category)
pandas_compliant_allegro_transactions.info()
pandas_compliant_allegro_transactions.describe()
pandas_compliant_allegro_transactions.describe(include=np.number)
W celu uzyskania informacji o pozostałych rodzajach kolumn możemy użyć parametrów:
Jeżeli chcemy, aby metoda describe() zwróciła nam wszystkie kolumny, wywołujemy ją z parametrem
pandas_compliant_allegro_transactions.describe(include='object')
pandas_compliant_allegro_transactions.describe(include='category')
pandas_compliant_allegro_transactions.loc[:,'datetime truncated to hour']=pandas_compliant_allegro_transactions.date.apply(lambda x : pd.Timestamp(year = x.year,
month = x.month,
day = x.day,
hour = x.hour))
pandas_compliant_allegro_transactions.describe(include='datetime')
pandas_compliant_allegro_transactions.head()
warnings.filterwarnings("ignore")
ls = lens.summarise(allegro_transactions)
explorer = lens.explore(ls)
explorer.describe()
Po analizie correlation_plot, widzimy wysoką korelację między oznaczeniem sprzedawcy jako allegro standard i jego oceną. Praktycznie nieskorelowane z jakimikolwiek innymi zmiennymi są sztuczne zmienne jak np. lp czy też zmienne identyfikacyjne jak item_id.
explorer.correlation_plot()
Column details umożliwa podsumowanie zmiennych ilościowych, jak i jakościowych. Podsumowanie zmiennych ilościowych zawiera trochę więcej informacji niż pandasowy describe
explorer.column_details('price')
explorer.column_details('main_category')
from bokeh.models import HoverTool
allegro_transactions.loc[:,'hour'] = allegro_transactions.date.apply(lambda timestamp : timestamp.time().hour)
df = allegro_transactions.groupby(['hour','main_category']).count()['lp'].unstack().fillna(0)
curve_dict = {colname:hv.Curve((np.arange(24), df.loc[:,colname]), label=colname) for colname in df.columns}
ndOverlay = hv.NdOverlay(curve_dict, kdims='kategoria')
ndOverlay.opts(title = "Liczba transakcji w ciągu dnia w podziale na kategorie",
tools=['hover','tap'], padding=0.1, width=960, height=540, show_grid=True,
ylabel='Liczba transakcji', xlabel='godzina')
ndOverlay.redim(x=hv.Dimension('x', range=(0, 23)),y=hv.Dimension('y',range=(0,12000)))
Widzimy po wykresach poniżej, że zmienne numeryczne przed przeskalowaniem nie nadają się do końca do użytku. Każda zmienna zawiera jakieś outliery (np. w przypadku ceny przeprowadzone zostały dwie transakcje związane ze sprzedażą nieruchomości). Po zmianie skali z jednostkowej na logarymiczną, otrzymaliśmy histogramy, które prezentują wartości o znacznie ładniejszych rozkładach.
fig = plt.figure(figsize = (16,16))
columns = ['price','it_quantity','it_seller_rating']
for i, colname in enumerate(columns, start=1):
v = allegro_transactions.loc[:,colname]
plt.subplot(3, 2, 2*i-1)
plt.hist(v.loc[v>0], label = f'{colname} before scaling to log')
plt.title(f'{colname} before scaling to log')
plt.subplot(3, 2, 2*i)
plt.hist(np.log(v.loc[v>0]), label = f'{colname} after scaling to log')
plt.title(f'{colname} after scaling to log')
Kolejnym krokiem w naszej eksploracji może być obliczenie agregatu związanego z różnymi kategoriami. Przykładowym i najbardziej sensownym jest agregat będący sumą wartości transakcji w podziale na kategorie.
aggregate = allegro_transactions.groupby(by='main_category', as_index=False).agg({'price':['sum','count']}).sort_values(('price','sum'), ascending=False)
plt.figure(figsize=(16,16))
plt.style.use('seaborn')
plt.barh(aggregate.main_category, aggregate.loc[:,('price','sum')], label = 'price sum', color='c')
plt.ylabel('Category', fontdict={'size':16})
plt.xlabel('Category value in PLN', fontdict={'size':16})
plt.title('Category values in PLN', fontdict={'size':32})
plt.show()